/*
 * @Descripttion: 在图片上绘制图案的类
 * @version: V1.0.0.1
 * @Author: zhaozhenzhuo
 * @Date: 2024-01-08 13:13:16
 * @LastEditors: zhaozhenzhuo
 * @LastEditTime: 2024-01-08 16:00:02
 */
/* eslint-disable lines-between-class-members */
/**
 * 传入图片url，在图片上绘制指定图案并展示。
 * 功能描述:
 *     创建画布（计算坐标缩放值）；
 *     设置绘制模式；
 *     设置样式；
 *     在指定坐标处绘制矩形；
 */

export default class {
	// 容器dom元素
	canvasWrapper: HTMLElement | null = null;
	// 画布dom元素
	canvas: HTMLCanvasElement | null = null;
	// 画布上下文对象
	ctx: CanvasRenderingContext2D | null = null;
	// 图片url
	imgUrl = '';
	// 图片宽度缩放比
	zoomWidthRatio = 1;
	// 图片高度缩放比
	zoomHeightRatio = 1;
	// 绘制模式 fill: 填充绘制 stroke: 描边绘制
	canvasMode: 'fill' | 'stroke' = 'stroke';
	// 绘制样式
	styleObj: { color: string; lineWidth: number } = {
		color: 'red', // 颜色
		lineWidth: 2 // 线宽
	};
	// 图像数据
	img: HTMLImageElement | null = null;

	constructor(canvasWrapper: HTMLElement) {
		if (!canvasWrapper) {
			throw new Error('请传入正确的容器dom！');
		}
		this.canvasWrapper = canvasWrapper;
	}

	// 创建画布 imgUrl:图片url非必传，不传就默认没有背景图片
	async createCanvas(imgUrl = ''): Promise<void> {
		const { canvasWrapper } = this;
		this.imgUrl = imgUrl;
		if (canvasWrapper) {
			this.destroyCanvas();

			const canvasWrapperWidth = canvasWrapper.offsetWidth;
			const canvasWrapperHeight = canvasWrapper.offsetHeight;

			const canvas = document.createElement('canvas');
			canvas.width = canvasWrapperWidth;
			canvas.height = canvasWrapperHeight;
			canvas.className = 'region-canvas';
			canvasWrapper.appendChild(canvas);
			this.canvas = canvas;
			this.ctx = canvas.getContext('2d');

			// 计算背景图片在画布上的缩放（为了缩放坐标值）
			if (this.imgUrl) {
				const imgRealSize = await this._initCanvasBackground();
				this.zoomWidthRatio = imgRealSize.width / canvasWrapperWidth;
				this.zoomHeightRatio = imgRealSize.height / canvasWrapperHeight;
			}
		}
	}

	// 设置绘制模式
	setCanvasMode(canvasMode: 'fill' | 'stroke'): void {
		if (canvasMode !== 'fill' && canvasMode !== 'stroke') {
			throw new Error('请传入正确的绘制模式！');
		}
		this.canvasMode = canvasMode;
	}

	// 设置样式
	setStyle(styleObj: { color: string; lineWidth: number }): void {
		if (Object.prototype.toString.call(styleObj) !== '[object Object]') {
			throw new Error('请传入正确的样式对象！');
		}
		const { color, lineWidth } = styleObj;
		if (color) {
			this.styleObj.color = color;
		}
		if (lineWidth) {
			this.styleObj.lineWidth = lineWidth;
		}
	}

	/* 在指定坐标处绘制矩形
     rectList:[{
        x: 0 矩形左上角与图片左上角水平距离
        y: 0 矩形左上角与图片左上角垂直距离
        width: 10 矩形宽度
        height: 10 矩形高度
     }]
  */
	drawRect(rectList: { x: number; y: number; width: number; height: number }[]): void {
		try {
			rectList.forEach((rect) => {
				const { x, y, width, height } = rect;
				if (!x && x !== 0) {
					throw new Error('x坐标不能为空！');
				} else if (!y && y !== 0) {
					throw new Error('y坐标不能为空！');
				} else if (!width) {
					throw new Error('宽度不能为空！');
				} else if (!height) {
					throw new Error('高度不能为空！');
				}
				if (this.canvasMode === 'fill' && this.ctx) {
					// 填充矩形
					this.ctx.fillStyle = this.styleObj.color; // 填充颜色
					this.ctx.fillRect(
						// 填充矩形位置和大小
						x / this.zoomWidthRatio,
						y / this.zoomHeightRatio,
						width / this.zoomWidthRatio,
						height / this.zoomHeightRatio
					);
				} else if (this.ctx) {
					// 描边矩形
					this.ctx.strokeStyle = this.styleObj.color; // 描边颜色
					this.ctx.lineWidth = this.styleObj.lineWidth; // 设置线宽
					this.ctx.strokeRect(
						// 描边矩形位置和大小
						x / this.zoomWidthRatio,
						y / this.zoomHeightRatio,
						width / this.zoomWidthRatio,
						height / this.zoomHeightRatio
					);
				}
			});
		} catch (err) {
			if (err !== 'StopIteration') {
				throw err;
			}
		}
	}

	/* 加载背景图并返回图片宽高 */
	_initCanvasBackground(): Promise<{ width: number; height: number }> {
		return new Promise<{ width: number; height: number }>((resolve, reject) => {
			if (!this.img || !this.img.width || !this.img.height) {
				this.img = new Image();
				this.img.src = this.imgUrl;

				this.img.onload = () => {
					if (this.img) {
						const width = this.img.width;
						const height = this.img.height;
						// 将背景图绘制到画布上
						if (this.canvas && this.ctx) {
							this.ctx.drawImage(this.img, 0, 0, this.canvas.width, this.canvas.height);
						}
						resolve({ width, height });
					}
					reject(new Error('图片加载失败'));
				};
				this.img.onerror = () => {
					reject(new Error('图片加载失败'));
				};
			} else {
				// 将背景图绘制到画布上
				if (this.canvas && this.ctx) {
					this.ctx.drawImage(this.img, 0, 0, this.canvas.width, this.canvas.height);
				}
				resolve({ width: this.img.width, height: this.img.height });
			}
		});
	}

	/* 销毁canvas */
	destroyCanvas(): void {
		if (this.canvas) {
			this.canvas.remove();
		}
		this.canvas = null;
		this.ctx = null;
	}

	/* 全部销毁 */
	destroyAll(): void {
		this.destroyCanvas();
		this.imgUrl = '';
		this.img = null;
		this.canvasWrapper = null;
	}
}
